// Copyright (c) 2023 Presto Labs Pte. Ltd.
// Author: tianqiang

#pragma once

#include "coin2/exchange/base/api_base/grpc/grpc_trade_client.h"
#include "coin2/exchange/base/order/processor.h"
#include "coin2/exchange/uniswap/api_util/auth_key.h"
#include "coin2/exchange/uniswap/symbology/product.h"
#include "coin2/service/web3/order_service.grpc.pb.h"

namespace coin2::exchange::uniswap::api_order::grpc {

enum UniswapGrpcSubTopicId : int {
  GRPC_PLACE_ORDER = 10000,
  GRPC_QUERY_ACCOUNT_BALANCE = 10001,
  GRPC_PROVIDE_LIQUIDITY = 10002,
  GRPC_WITHDRAW_LIQUIDITY = 10003,
  GRPC_QUERY_NFT_TOKEN_INFO = 10004,
};

class UniswapGrpcTradeClient : public coin2::exchange::base::api_base::grpc::GrpcTradeClient,
                               public coin2::exchange::base::order::NativePrivateClient {
 public:
  using GrpcTradeClient = coin2::exchange::base::api_base::grpc::GrpcTradeClient;
  using GrpcContext = coin2::exchange::base::api_base::grpc::GrpcContext;
  using Web3OrderService = coin2::service::Web3OrderService;
  using OrderExecution = GrpcTradeClient::OrderExecution;
  using UniswapProduct = coin2::exchange::uniswap::symbology::UniswapProduct;
  using NativeClientConfig = coin2::exchange::order::OrderConnectionConfig;

  UniswapGrpcTradeClient(
      const MarketExchangeApi& mea,
      const NativeClientConfig& config,
      bool is_grpc_client);

  void PlaceOrder(const OrderExecution&) override;
  void CancelOrder(const OrderExecution&) override;

  void SubmitLiquidity(const LiquiditySpec&) override;

  void QueryAccountBalance(const std::set<std::string>& currencies);
  void QueryNftTokenInfo(const std::string& symbol);

  std::shared_ptr<AsioHttpContext> PlaceOrderNorm(const OrderExecution&) { return {}; }
  std::shared_ptr<AsioHttpContext> CancelOrderNorm(const OrderExecution&) { return {}; }

 private:
  void ProvideLiquidity(const LiquiditySpec&);
  void WithdrawLiquidity(const LiquiditySpec&);

  std::shared_ptr<::coin2::service::QuerySubmitOrderRequestProto> GetPlaceOrderRequest(
      const OrderSpec& order_spec);

  std::shared_ptr<GrpcContext> GetGrpcContextWithTimeout(unsigned int timeout);

  const static std::string web3_default_internal_grpc_host_;
  const static int32_t web3_default_internal_grpc_host_port_;
  const static std::string web3_default_blockchain_name_;
  std::string blockchain_name_;
  std::shared_ptr<::grpc::Channel> channel_;
  std::unique_ptr<Web3OrderService::Stub> stub_;
  std::unique_ptr<UniswapGrpcAuth> auth_;
};

}  // namespace coin2::exchange::uniswap::api_order::grpc
